package com.zone.editor.pixel;

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ColorSpace;
import android.graphics.Paint;
import android.graphics.Point;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.RelativeLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.RequiresApi;
import com.zone.editor.inter.Editor;
import com.zone.editor.inter.EditorView;
import com.zone.editor.CustomEffect;
import com.zone.editor.utils.AssetUtil;
import com.zone.editor.utils.ImageUtil;
import com.zone.editor.view.ImageFilterView;
import com.zone.editor.enums.Filter;
import com.zone.editor.inter.OnSaveBitmap;
import com.zone.editor.photoEditor.R;
import com.zone.editor.view.FilterImageView;
import com.zone.sdk.isd.util.ColorUtil;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class PixelEditorView extends RelativeLayout implements EditorView {

    private static final String TAG = PixelEditorView.class.getSimpleName();

    private FilterImageView mImgSource;
    private PixelDrawingView mDrawingView;
    private ImageFilterView mImageFilterView;
    private Bitmap templateBitmap;
    private boolean clipSourceImage;
    private static final int imgSrcId = 1, shapeSrcId = 2, glFilterId = 3;

    public PixelEditorView(Context context) {
        super(context);
        init(null);
    }

    public PixelEditorView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(attrs);
    }

    public PixelEditorView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init(attrs);
    }

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public PixelEditorView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(attrs);
    }

    @Override
    public ViewGroup getView() {
        return this;
    }

    private void init(@Nullable AttributeSet attrs) {

        //Setup image attributes
        mImgSource = new FilterImageView(getContext());
        mImgSource.setImageResource(R.drawable.pic_transparent);
//        mImgSource.setImageBitmap(createBg());
        LayoutParams sourceParam = setupImageSource(attrs);

        //Setup GLSurface attributes
        mImageFilterView = new ImageFilterView(getContext());
        LayoutParams filterParam = setupFilterView();
        //Setup drawing view
        mDrawingView = new PixelDrawingView(getContext());
//        mDrawingView.setBackgroundColor(Color.BLUE);
        mDrawingView.enableDrawing(true);
        LayoutParams brushParam = setupDrawingView();

        //Add image source
        addView(mImgSource, sourceParam);
        //Add Gl FilterView
        addView(mImageFilterView, filterParam);
        //Add brush view
        addView(mDrawingView, brushParam);

        if (attrs != null) {
            TypedArray attributes = getContext().obtainStyledAttributes(attrs, R.styleable.PixelEditorView);
//            Drawable templateSource = attributes.getDrawable(R.styleable.PixelEditorView_template_source);
            boolean isFront = attributes.getBoolean(R.styleable.PixelEditorView_is_front, true);
            if (isFront){
                templateBitmap = AssetUtil.getAsset(getContext(), "isd_front.png");
            }else {
                templateBitmap = AssetUtil.getAsset(getContext(), "isd_tail.png");
            }
            if (templateBitmap != null) {
                float density = getResources().getDisplayMetrics().density;
//                bitmap = com.zone.sdk.isd.util.ImageUtil.transImage(bitmap, with/density, height/density);
                int[] bytes = ImageUtil.getPixels(templateBitmap);
//                System.out.println("pixels size="+bytes.length);

                mDrawingView.setTemplateBitmap(templateBitmap);
                mDrawingView.setTemplateColor(bytes);
                mDrawingView.setDensity(density);
                mDrawingView.setFront(isFront);

                int blankColor = attributes.getColor(R.styleable.PixelEditorView_blank_color, Color.BLACK);
                List<Integer> colors = new ArrayList<>();
                colors.add(blankColor);
                mDrawingView.setBlankColor(colors);
                Point lastColorPoint = null;
                int width = templateBitmap.getWidth();
                Map<Integer, Point> cacheColorIndex = new HashMap<>();
                for (int i = 0; i < bytes.length; i++) {
                    int color = bytes[i];
                    int widthIndex = i % width;
                    int heightIndex = i / width;
                    if (blankColor == color){
                        cacheColorIndex.put(i, lastColorPoint);
                    }else {
                        Point point = new Point();
                        point.set(widthIndex, heightIndex);
                        lastColorPoint = point;
                    }
                }
                mDrawingView.setCacheColorIndex(cacheColorIndex);
            }
            Drawable imgSrcDrawable = attributes.getDrawable(R.styleable.PixelEditorView_background_source);
            if (imgSrcDrawable != null) {
                mImgSource.setImageDrawable(imgSrcDrawable);
            }

            int radius = attributes.getInt(R.styleable.PixelEditorView_radius, 1);
            if (radius > 0){
                mDrawingView.setRadius(radius);
            }
            Log.d(TAG, "radius="+radius);
        }
    }

    private Bitmap createBg(){
        int picw = 1920;
        int pich = 1080;
        Bitmap mBitmap = Bitmap.createBitmap(picw, pich,
                Bitmap.Config.ARGB_8888);
        int[] pix = new int[picw * pich];
        for (int y = 0; y < pich; y++)
            for (int x = 0; x < picw; x++)
            {
                int index = y * picw + x;
                int r = ((pix[index] >> 16) & 0xff)|0xff;
                int g = ((pix[index] >> 8) & 0xff)|0xff;
                int b =( pix[index] & 0xff)|0xff;
                pix[index] = 0xff000000 | (r << 16) | (g << 8) | b;
            }
        mBitmap.setPixels(pix, 0, picw, 0, 0, picw, pich);
        return mBitmap;
    }

    @SuppressLint("Recycle")
    private LayoutParams setupImageSource(@Nullable AttributeSet attrs) {
        mImgSource.setId(imgSrcId);
        mImgSource.setAdjustViewBounds(true);
        mImgSource.setScaleType(ImageView.ScaleType.CENTER_INSIDE);

        if (attrs != null) {
            TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.PhotoEditorView);
            Drawable imgSrcDrawable = a.getDrawable(R.styleable.PhotoEditorView_photo_src);
            if (imgSrcDrawable != null) {
                mImgSource.setImageDrawable(imgSrcDrawable);
            }
        }

        int widthParam = ViewGroup.LayoutParams.MATCH_PARENT;
        if (clipSourceImage) {
            widthParam = ViewGroup.LayoutParams.WRAP_CONTENT;
        }
        LayoutParams params = new LayoutParams(
                widthParam, ViewGroup.LayoutParams.WRAP_CONTENT);
        params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);

        return params;
    }


    private LayoutParams setupDrawingView() {
        mDrawingView.setVisibility(GONE);
        mDrawingView.setId(shapeSrcId);

        // Align drawing view to the size of image view
        LayoutParams params = new LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);
        params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
//        params.addRule(RelativeLayout.ALIGN_TOP, imgSrcId);
//        params.addRule(RelativeLayout.ALIGN_BOTTOM, imgSrcId);
        params.addRule(RelativeLayout.ALIGN_LEFT, imgSrcId);
        params.addRule(RelativeLayout.ALIGN_RIGHT, imgSrcId);
        return params;
    }


    private LayoutParams setupFilterView() {
        mImageFilterView.setVisibility(GONE);
        mImageFilterView.setId(glFilterId);

        //Align brush to the size of image view
        LayoutParams params = new LayoutParams(
                ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        params.addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE);
        params.addRule(RelativeLayout.ALIGN_TOP, imgSrcId);
        params.addRule(RelativeLayout.ALIGN_BOTTOM, imgSrcId);

        return params;
    }


    /**
     * Source image which you want to edit
     *
     * @return source ImageView
     */
    @Override
    public ImageView getSource() {
        return mImgSource;
    }

    @Override
    public PixelDrawingView getDrawingView() {
        return mDrawingView;
    }


    @Override
    public Editor build(Editor.Builder builder) {
        return new PixelEditorImpl(builder);
    }


    public void saveFilter(@NonNull final OnSaveBitmap onSaveBitmap) {
        if (mImageFilterView.getVisibility() == VISIBLE) {
            mImageFilterView.saveBitmap(new OnSaveBitmap() {
                @Override
                public void onBitmapReady(final Bitmap saveBitmap) {
                    Log.e(TAG, "saveFilter: " + saveBitmap);
                    mImgSource.setImageBitmap(saveBitmap);
                    mImageFilterView.setVisibility(GONE);
                    onSaveBitmap.onBitmapReady(saveBitmap);
                }

                @Override
                public void onFailure(Exception e) {
                    onSaveBitmap.onFailure(e);
                }
            });
        } else {
            onSaveBitmap.onBitmapReady(mImgSource.getBitmap());
        }
    }

    public void setFilterEffect(Filter filterType) {
        mImageFilterView.setVisibility(VISIBLE);
        mImageFilterView.setSourceBitmap(mImgSource.getBitmap());
        mImageFilterView.setFilterEffect(filterType);
    }

    public void setFilterEffect(CustomEffect customEffect) {
        mImageFilterView.setVisibility(VISIBLE);
        mImageFilterView.setSourceBitmap(mImgSource.getBitmap());
        mImageFilterView.setFilterEffect(customEffect);
    }

    @Override
    public void setClipSourceImage(boolean clip) {
        clipSourceImage = clip;
        LayoutParams param = setupImageSource(null);
        mImgSource.setLayoutParams(param);
    }

    /**
     * 设置矩形区域画笔颜色
     * @param rect
     * @param color
     */
    public void setStaticRect(RectF rect, int color){
        mDrawingView.setStaticRect(rect, color);
    }

    public void setTemplateBitmap(Bitmap bitmap) {
        if (bitmap != null){
            templateBitmap = bitmap;
            mDrawingView.setTemplateColor(ImageUtil.getPixels(bitmap));
        }
    }

    @Override
    public Bitmap getTemplateBitmap() {
        return templateBitmap;
    }

    @Override
    public void clearAll() {
        mDrawingView.clearAll();
    }

    public void setBlankColor(List<Integer> blankColor) {
        mDrawingView.setBlankColor(blankColor);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        Log.d(TAG, "onSizeChanged="+w);
        super.onSizeChanged(w, h, oldw, oldh);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);

        Log.d(TAG, "onDraw "+getWidth());
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        Log.d(TAG, "onMeasure "+widthMeasureSpec+ " mDrawingView.getMeasuredWidth="+mDrawingView.getMeasuredWidth());
    }

    @Override
    public boolean onGenericMotionEvent(MotionEvent event) {
        Log.d(TAG, "onGenericMotionEvent="+event.getAction());
        return super.onGenericMotionEvent(event);
    }
}
